﻿/* CircleFitSolver_OpenCV.h
 * 
 * Copyright (C) 2020, 2021 Yuan LI
 * email:18069211@qq.com
 * https://blog.csdn.net/liyuanbhu
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef OPENCVCIRCLEFITSOLVER_H
#define OPENCVCIRCLEFITSOLVER_H

#include <complex>
#include <vector>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multimin.h>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;

/**
 * @brief circleLeastFit 最小二乘法拟合圆
 * @param points 数据点
 * @param center_x [out] 圆心坐标
 * @param center_y [out] 圆心坐标
 * @param radius [out]  半径
 * @return
 */
bool circleLeastFit(const std::vector<cv::Point2i> &points, double &center_x, double &center_y, double &radius);

class CircleFitSolver_OpenCV
{
public:
    CircleFitSolver_OpenCV();
    ~CircleFitSolver_OpenCV();
    void setMaxIter(int iter) {m_max_iter = iter;}

    /**
     * @brief circleFitL1  拟合圆，拟合判据为数据点到拟合圆的距离绝对值之和最小。
     * @param points 输入参数，存储各个数据点。
     * @param center_x radius > 0 时作为迭代算法的初始值。计算完成后返回拟合圆的圆心 X 坐标
     * @param center_y radius > 0 时作为迭代算法的初始值。计算完成后返回拟合圆的圆心 Y 坐标
     * @param radius   radius < 0 时，用最小二乘拟合的结果作为迭代算法的初始值。计算完成后返回拟合圆的半径。
     * @return true 表示拟合成功，否则拟合失败。
     */
    bool circleFitL1(const vector<cv::Point2i> &points, double &center_x, double &center_y, double &radius);
private:
    gsl_multimin_function m_function;
    gsl_multimin_fminimizer * m_fminimizer;

    int m_max_iter; // 迭代算法的最大迭代次数

    gsl_vector *m_start_point; // 迭代算法的初始值
    gsl_vector *m_step_size; // 迭代算法的初始步长

    void setStartPoint(double center_x, double center_y, double radius);
    static double L1_distance(const gsl_vector * v, void * params);
};

#endif // OPENCVCIRCLEFITSOLVER_H
